package org.syntaxlisp.core.match.tree;

import org.syntaxlisp.core.ParseException;
import org.apache.commons.collections4.CollectionUtils;

import java.util.*;

/**
 * @author HuangYijun
 * @data 2023-10-12 10:04
 **/
public class CurPvtProvider {

    private Set<Integer> startHistory;

    private Map<Integer, Queue<NewCurPvt>> pvtQueueMap;

    private Map<Integer, Map<String, List<NewCurPvt>>> refPvtMap;

    private static final Queue<NewCurPvt> EMPTY_QUEUE = new ArrayDeque<>(0);

    public CurPvtProvider () {
        pvtQueueMap = new HashMap<>();
        refPvtMap = new HashMap<>();
        startHistory = new HashSet<>();
    }

    public boolean containsPvt (Integer nextOffset) {
        return pvtQueueMap.containsKey(nextOffset);
    }

    public boolean containsStartPvt (Integer startOffset) {
        return startHistory.contains(startOffset);
    }

    public Optional<NewCurPvt> poll (Integer nextOffset) {
        return Optional.ofNullable(pvtQueueMap.getOrDefault(nextOffset, EMPTY_QUEUE)
                                              .poll());
    }

    public boolean isEmpty () {
        return pvtQueueMap.isEmpty();
    }

    public void offer (NewCurPvt newCurPvt) {
        if (!newCurPvt.isReducing()) {
            pvtQueueMap.computeIfAbsent(newCurPvt.getNextOffset(), nextOffset -> new ArrayDeque<>())
                       .offer(newCurPvt);
            startHistory.add(newCurPvt.getCurOffset());
        } else {
            throw new ParseException("Reducing CurPvt can not be offered!");
        }
    }

    public void offerRefPvt (NewCurPvt refPvt) {
        if (refPvt.isRefPvt() && refPvt.isReducing()) {
            List<NewCurPvt> refPvtList = refPvtMap.computeIfAbsent(refPvt.getCurOffset(), start -> new HashMap<>())
                                                  .computeIfAbsent(refPvt.requireRef(), def -> new ArrayList<>());
            if (!refPvtList.contains(refPvt)) {
                refPvtList.add(refPvt);
            }
        } else {
            throw new ParseException("Non-Reducing-Ref CurPvt can not be offered!");
        }
    }

    public List<NewCurPvt> getRefPvtList (Integer startOffset, String def) {
        return def != null
                ? refPvtMap.getOrDefault(startOffset, Collections.emptyMap())
                           .getOrDefault(def, Collections.emptyList())
                : Collections.emptyList();
    }

    public Map<String, List<NewCurPvt>> getRefPvtMap (Integer startOffset) {
        return startOffset != null
               ? refPvtMap.getOrDefault(startOffset, Collections.emptyMap())
               : Collections.emptyMap();
    }

    public boolean removeQueue (int nextOffset) {
        Queue<NewCurPvt> original = pvtQueueMap.get(nextOffset);
        if (!CollectionUtils.isEmpty(original)) {
            return false;
        }
        if (original != null) {
            pvtQueueMap.remove(nextOffset);
        }
        return true;
    }


}
